----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date:    07:56:09 04/03/2008 
-- Design Name: 
-- Module Name:    STAGE_MEM - Behavioral 
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description: 
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
--
----------------------------------------------------------------------------------
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;

ENTITY STAGE_MEM IS
  PORT (CLK          : IN  std_logic;
        RST          : IN  std_logic;
        DIP          : IN  std_logic_vector(3 DOWNTO 0);
        BUTTON       : IN  std_logic_vector(1 DOWNTO 0);
        EXMEM_IR     : IN  std_logic_vector(31 DOWNTO 0);
        EXMEM_B      : IN  std_logic_vector(15 DOWNTO 0);
        EXMEM_ALUOUT : IN  std_logic_vector(15 DOWNTO 0);
        LED          : OUT std_logic_vector(3 DOWNTO 0);
        MEMWB_IR     : OUT std_logic_vector(31 DOWNTO 0);
        MEMWB_ALUOUT : OUT std_logic_vector(15 DOWNTO 0);
        MEMWB_LMD    : OUT std_logic_vector(15 DOWNTO 0)
        );
END STAGE_MEM;

ARCHITECTURE Behavioral OF STAGE_MEM IS
  COMPONENT data_memory
    PORT (
      addr : IN  std_logic_vector(7 DOWNTO 0);
      clk  : IN  std_logic;
      din  : IN  std_logic_vector(15 DOWNTO 0);
      dout : OUT std_logic_vector(15 DOWNTO 0);
      we   : IN  std_logic);
  END COMPONENT;

  SIGNAL we            : std_logic;
  SIGNAL mem_out       : std_logic_vector(15 DOWNTO 0);
  SIGNAL mapped_out    : std_logic_vector(15 DOWNTO 0);
  SIGNAL button_reg    : std_logic_vector(1 DOWNTO 0) := (OTHERS => '0');
  SIGNAL use_mapped_io : std_logic;
BEGIN
  -- For the memory mapped IO addresses, the RAM will still read and write
  -- whenever they are accessed; however, they will not be used
  data_memory_i : data_memory
    PORT MAP (
      addr => EXMEM_ALUOUT(7 DOWNTO 0),
      clk  => CLK,
      din  => EXMEM_B,
      dout => mem_out,
      we   => we);

  -- purpose: Manage MEM stage
  -- type   : sequential
  -- Handle we signal connected to the memory bank
  PROCESS (EXMEM_IR, EXMEM_ALUOUT, DIP, button_reg) IS
  BEGIN  -- PROCESS
    CASE EXMEM_IR(28 DOWNTO 26) IS
      WHEN "001" =>                                     -- Load
        we <= '0';
        CASE EXMEM_ALUOUT(8 DOWNTO 0) IS
          WHEN "100000000" =>                           -- Switches
            use_mapped_io <= '1';
            mapped_out    <= ("000000000000"&DIP);
          WHEN "100000001" =>                           -- Button 0
            use_mapped_io <= '1';
            mapped_out    <= ("000000000000000"&button_reg(0));
          WHEN "100000010" =>                           -- Button 1
            use_mapped_io <= '1';
            mapped_out    <= ("000000000000000"&button_reg(1));
          WHEN OTHERS =>
            use_mapped_io <= '0';
            mapped_out    <= (OTHERS => '0');
        END CASE;
      WHEN "010" =>                                     -- Store
        we         <= '1';
        mapped_out <= (OTHERS => '0');
        IF EXMEM_ALUOUT(8 DOWNTO 0) = "100000011" THEN  -- LEDs
          use_mapped_io <= '1';
        ELSE
          use_mapped_io <= '0';
        END IF;
      WHEN OTHERS =>
        we            <= '0';
        use_mapped_io <= '0';
        mapped_out    <= (OTHERS => '0');
    END CASE;
  END PROCESS;

  -- purpose: Handle memory mapped IO
  -- type   : sequential
  PROCESS (CLK) IS
  BEGIN  -- PROCESS
    IF CLK'event AND CLK = '1' THEN     -- rising clock edge
      IF RST = '1' THEN                 -- synchronous reset (active high)
        button_reg <= (OTHERS => '0');
      ELSE
        IF EXMEM_IR(28 DOWNTO 26) = "010" THEN            -- Store
          IF EXMEM_ALUOUT(8 DOWNTO 0) = "100000011" THEN  -- LEDs
            LED <= EXMEM_B(3 DOWNTO 0);
          END IF;
          IF BUTTON(0) = '1' THEN
            button_reg(0) <= '1';
          END IF;

          IF BUTTON(1) = '1' THEN
            button_reg(1) <= '1';
          END IF;
        ELSIF EXMEM_IR(28 DOWNTO 26) = "001" THEN  -- Load
          CASE EXMEM_ALUOUT(8 DOWNTO 0) IS
            WHEN "100000001" =>                    -- Button 0
              button_reg(0) <= BUTTON(0);
            WHEN "100000010" =>                    -- Button 1
              button_reg(1) <= BUTTON(1);
            WHEN OTHERS =>
              IF BUTTON(0) = '1' THEN
                button_reg(0) <= '1';
              END IF;

              IF BUTTON(1) = '1' THEN
                button_reg(1) <= '1';
              END IF;
          END CASE;
        ELSE
          IF BUTTON(0) = '1' THEN
            button_reg(0) <= '1';
          END IF;

          IF BUTTON(1) = '1' THEN
            button_reg(1) <= '1';
          END IF;
        END IF;
      END IF;
    END IF;
  END PROCESS;

  PROCESS (CLK) IS
  BEGIN  -- PROCESS
    IF CLK'event AND CLK = '1' THEN     -- rising clock edge
      IF RST = '1' THEN                 -- synchronous reset (active high)
        MEMWB_IR     <= (OTHERS => '0');
        MEMWB_ALUOUT <= (OTHERS => '0');
        MEMWB_LMD    <= (OTHERS => '0');
      ELSE
        MEMWB_IR     <= EXMEM_IR;
        MEMWB_ALUOUT <= EXMEM_ALUOUT;
        IF use_mapped_io = '0' THEN
          MEMWB_LMD <= mem_out;
        ELSE
          MEMWB_LMD <= mapped_out;
        END IF;
      END IF;
    END IF;
  END PROCESS;
END Behavioral;

